#!/usr/bin/env python
#
# maintain_lockfile.py
#
# Version : 0.7
# Date : 20080524
#
# Author : Bernard Czenkusz
# Email  : bernie@skipole.co.uk


# maintain_lockfile - run as part of skipolemonitor, used to stop more
# than one instance of the program running by maintaining a lockfile
#
# Copyright (c) 2007 Bernard Czenkusz
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#

"""Maintain_lockfile contains functions to:
   creates the lockfile in net.net_cfg["NETWORK_DATA_FOLDER"]
   refreshes the lockfile timestamp every second
   deletes the lockfile"""

import os
import time
import net

lockfile=os.path.join(net.net_cfg["NETWORK_DATA_FOLDER"], "lockfile")

def start_lockfile():
    """Check if a lock file exists in the data directory, and if not create one
       If one does exist - and its timestamp is recent, then this indicates
       another instance of skipole monitor is running, so exit with an
       error message."""
    global lockfile
    #
    if not os.path.exists(lockfile):
        # lockfile does not exist, so create one and carry on
        try:
            fp = open(lockfile, "w")
            fp.write("This lockfile is used to stop more than one instance of Skipole Monitor running")
            fp.close()
        except:
            return 9, "Error writing lockfile, perhaps more than one instance of SkipoleMonitor has been started"
    else:
        # The lockfile exists, check its timestamp
        time_since_file_timestamp = time.time() - os.stat(lockfile).st_atime
        # If this is negative, i.e. the file timestamp was done in the future, then probably
        # the system clock has changed, remove the file and exit
        if time_since_file_timestamp < 0:
            os.remove(lockfile)
            return 10, "Error writing lockfile, perhaps more than one instance of SkipoleMonitor has been started"
        # if less than 5 seconds old, its likely another instance of skipolemonitor
        # is running, so exit with an error message
        if time_since_file_timestamp < 5:
            return 11, "Exit program - more than one instance of SkipoleMonitor has been started"
        else:
            # So a lockfile exists, but its older than 4 seconds - possibly due to a previouse
            # instance of this program running which was not deleted if the program shut down
            # incorrectly, so try to update its timestamp
            try:
                os.utime(lockfile, None)
            except:
                # Cant update it - so somethings wrong
                return 12, "Error writing lockfile, perhaps more than one instance of SkipoleMonitor has been started"
    # So, a lockfile is created, or an if more than 4 seconds old, its timestamp is updated
    return 0, "All OK"


def lockfile_loop():
    """Continual loop to update the lockfile timestamp at one second intervals.
       Loop only exits when the net.PROGRAM_SHUTDOWN flag is true"""
    global lockfile
    #
    # do the loop
    while not net.PROGRAM_SHUTDOWN:
        # touch the lockfile to update its timestamp
        try:
            os.utime(lockfile, None)
        except:
            if not os.path.exists(lockfile):
                # lockfile does not exist, perhaps it has been deleted, so create one and carry on
                fp = open(lockfile, "w")
                fp.write("This lockfile is used to stop more than one instance of Skipole Monitor running")
                fp.close()
        time.sleep(1)


def close():
    "Called when program exits - deletes the lockfile"
    global lockfile
    try:
        os.remove(lockfile)
    except:
        # dont bother with any errors - just continue
        pass
    return

